home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Src / tk-glue.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-13  |  11.3 KB  |  401 lines

  1. /*
  2.  *
  3.  * t k - g l u e . c         - Glue function between the scheme and Tk worlds
  4.  *
  5.  * Copyright ⌐ 1993-1996 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
  6.  * 
  7.  *
  8.  * Permission to use, copy, and/or distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted, provided
  10.  * that both the above copyright notice and this permission notice appear in
  11.  * all copies and derived works.  Fees for distribution or use of this
  12.  * software or derived works may only be charged with express written
  13.  * permission of the copyright holder.  
  14.  * This software is provided ``as is'' without express or implied warranty.
  15.  *
  16.  * This software is a derivative work of other copyrighted softwares; the
  17.  * copyright notices of these softwares are placed in the file COPYRIGHTS
  18.  *
  19.  *
  20.  *            Author: Erick Gallesio [eg@unice.fr]
  21.  *    Creation date: 19-Feb-1993 22:15
  22.  * Last file update: 13-Jun-1996 19:10
  23.  *
  24.  *
  25.  */
  26.  
  27. #ifdef USE_TK
  28. #include "stk.h"
  29. #include "tk-glue.h"
  30. #include "gc.h"
  31. #include "tkInt.h"
  32.  
  33. #define MAXARG 64    /* Max args on stack. Use malloc if greater */
  34.  
  35. /* Scheme objects used to represent the "." pseudo widget and its name */
  36. SCM STk_root_window;
  37. SCM STk_root_window_name;
  38.  
  39. /* Last result of Tcl_GlobalEval (as a SCM object rather than a string) */
  40. SCM STk_last_Tk_result;
  41.  
  42. static SCM TkResult2Scheme(Tcl_Interp *interp)
  43. {
  44.   register char*s= interp->result;
  45.   register SCM tmp1, tmp2, z, port;
  46.   SCM result = NIL;
  47.   int eof;
  48.  
  49.   if (*s) {
  50.     /* Create a string port to read in the result */
  51.     port   = STk_internal_open_input_string(s);
  52.     result = STk_internal_read_from_string(port, &eof, TRUE);
  53.     if (result == Sym_dot) result = STk_root_window;
  54.  
  55.     if (!eof) {
  56.       /*  Result was a list of value, build a proper Scheme list */
  57.       tmp1 = result = LIST1(result);
  58.       for ( ; ; ) {
  59.     z = STk_internal_read_from_string(port, &eof, TRUE);
  60.     if (z == EVAL_ERROR || EOFP(z)) break;
  61.     if (z == Sym_dot) z = STk_root_window;
  62.     NEWCELL(tmp2, tc_cons);
  63.     CAR(tmp2) = z; 
  64.     CDR(tmp1) = tmp2;
  65.     tmp1      = tmp2;
  66.       }
  67.       CDR(tmp1) = NIL;
  68.     }
  69.     /* close_string_port(port); */
  70.   }
  71.  
  72.   Tcl_ResetResult(interp); 
  73.   return (result == EVAL_ERROR)? UNDEFINED: result;
  74. }
  75.  
  76. char *STk_convert_for_Tk(SCM obj, SCM *res)
  77. {
  78.   switch (TYPE(obj)) {
  79.     case tc_symbol:    *res = obj; return PNAME(obj);
  80.     case tc_integer:
  81.     case tc_bignum:
  82.     case tc_flonum:    *res = STk_number2string(obj, UNBOUND); return CHARS(*res);
  83.     case tc_string:    *res = obj; return CHARS(obj);
  84.     case tc_tkcommand: return (obj->storage_as.tk.data)->Id;
  85.     case tc_keyword:   *res = obj; return obj->storage_as.keyword.data;
  86.     case tc_boolean:   return (obj == Truth)? "#t" : "#f";
  87.     default:           /* Ok, take the big hammer (i.e. use a string port for 
  88.             * type coercion) Here, use write (and not display) 
  89.             * since it handles complex data structures containing
  90.             * eventually special chars which must be escaped
  91.             * Ex: (bind .w "<Enter>" '(display "<Enter>"))
  92.             *     First <Enter> is unquotted and second is not
  93.             */
  94.                {
  95.              SCM port;
  96.              
  97.              port = STk_open_output_string();
  98.              STk_print(obj, port, TK_MODE); 
  99.              *res = STk_get_output_string(port);
  100.              return CHARS(*res);
  101.                }
  102.   }
  103. }
  104.  
  105.  
  106. SCM STk_execute_Tcl_lib_cmd(SCM cmd, SCM args, SCM env, int eval_args)
  107. {
  108.   char *buffer[MAXARG+2];
  109.   int tkres;
  110.   char **argv            = buffer;
  111.   int argc             = STk_llength(args);
  112.   SCM conv_res, start  = args;
  113.   struct Tk_command *W = cmd->storage_as.tk.data;
  114.  
  115.  
  116.   if (argc >= MAXARG) {
  117.     /* allocate dynamically the argv array (one extra for argv[0] and one 
  118.      * for the NULL terminator -dsf
  119.      */
  120.     argv=(char **) must_malloc((argc+2) * sizeof(char *));
  121.   }
  122.  
  123.   /* 
  124.    * conv_res is (roughly) a vector of the values returned by convert_for_Tk. 
  125.    * It serves only to have pointers in the stack on the converted values. 
  126.    * This permits to avoid GC problems (i.e. a GC between 1 and argc 
  127.    * whereas convert_for_Tk has created new cells in a previous iteration 
  128.    */
  129.   conv_res = STk_makevect(argc+2, NIL);
  130.  
  131.   /* First initialize an argv array */
  132.   argv[0] = cmd->storage_as.tk.data->Id;
  133.   
  134.   for (argc = 1; NNULLP(args); argc++, args=CDR(args)) {
  135.     if (NCONSP(args)) Err("Malformed list of arguments", start);
  136.     argv[argc] = STk_convert_for_Tk(eval_args ? STk_eval(CAR(args), env):CAR(args), 
  137.                               &(VECT(conv_res)[argc]));
  138.   }
  139.   argv[argc] = NULL;
  140.  
  141.   /* Now, call the Tk library function */
  142.   Tcl_ResetResult(STk_main_interp);
  143.  
  144.   tkres = (*W->fct)(W->ptr, STk_main_interp, argc, argv);
  145.   
  146.   if (argv != buffer) {
  147.     /* argv was allocated dynamically. Dispose it */
  148.     free(argv);
  149.   }
  150.  
  151.   /* return result as a string or "evaluated" depending of string_result field */
  152.   if (tkres == TCL_OK)
  153.     return TkResult2Scheme(STk_main_interp);
  154.   
  155.   Err(STk_main_interp->result, NIL);
  156. }
  157.  
  158. /******************************************************************************
  159.  *
  160.  * Callback management
  161.  *
  162.  ******************************************************************************/
  163.  
  164. static Tcl_HashTable Tk_callbacks;
  165.  
  166.  
  167. int STk_valid_callback(char *s, void **closure)
  168. {
  169.   /* A callback is valid iff it is of the form "#pxxxx" where xxxx is composed
  170.    * only of hexadecimal digit.
  171.    * Furthermore, the given address must  be a valid adress
  172.    */
  173.   int l = strlen(s);
  174.   char *p;
  175.  
  176.   *closure = NULL;
  177.   if (l > 2) {
  178.     if (s[0] == '#' && s[1] == 'p') {
  179.       /* Verify that the rest of the string only contains hexadecimal digits */
  180.       for (p = s + 2; *p; p++)
  181.     if (!isxdigit(*p)) return FALSE;
  182.  
  183.       sscanf(s+2, "%lx", (unsigned long) closure);
  184.       if (!STk_valid_address((SCM) *closure)) return FALSE;
  185.     }
  186.   }
  187.   return TRUE;
  188. }
  189.  
  190. void STk_add_callback(char *key1, char *key2, char *key3, SCM closure)
  191. {
  192.   Tcl_HashEntry *entry;
  193.   Tcl_HashTable *secondary_hash_table;
  194.   int new;
  195.   char key[200]; /* Largely sufficient */
  196.  
  197.   if (*key2) {
  198.     /* We have two keys. Use a secondary hash table */
  199.     if (entry=Tcl_FindHashEntry(&Tk_callbacks, key1))
  200.       /* Key already in hash table */
  201.       secondary_hash_table = Tcl_GetHashValue(entry);
  202.     else {
  203.       secondary_hash_table = (Tcl_HashTable *) must_malloc(sizeof(Tcl_HashTable));
  204.       Tcl_InitHashTable(secondary_hash_table, TCL_STRING_KEYS);
  205.       entry = Tcl_CreateHashEntry(&Tk_callbacks, (char *) key1, &new);
  206.       Tcl_SetHashValue(entry, secondary_hash_table);
  207.     }
  208.     
  209.     /* Enter a new key (obtained from key2 and key3) in the hash table.
  210.      * Don't worry about old value: since it is no more pointed by the 
  211.      * hash table, it will be garbaged at next GC run
  212.      */
  213.     sprintf(key, "%s#%s", key2, key3);/* Create a new key from key2 and key3 */
  214.     entry = Tcl_CreateHashEntry(secondary_hash_table, key, &new);
  215.     Tcl_SetHashValue(entry, closure); 
  216.   }
  217.   else {
  218.     /* Only one key. No need for a secondary hash table */
  219.     entry =Tcl_CreateHashEntry(&Tk_callbacks, key1, &new);
  220.     Tcl_SetHashValue(entry, closure);
  221.   }
  222. }
  223.  
  224.  
  225. void STk_delete_callback(char *key)
  226. {
  227.   /*
  228.    * key is destroyed. We only need to free the entry associated to it in the 
  229.    * Tk_callback hash table (if it exists).
  230.    */
  231.   Tcl_HashEntry *entry;
  232.   Tcl_HashTable *secondary_hash_table;
  233.  
  234.   if (entry=Tcl_FindHashEntry(&Tk_callbacks, key)) {
  235.     if (*key != 'a' && strncmp(key, "after#", 6) != 0) {
  236.       /* Delete the secondary hash table associated to this entry */
  237.       secondary_hash_table = Tcl_GetHashValue(entry);
  238.       Tcl_DeleteHashTable(secondary_hash_table);
  239.       free(secondary_hash_table);
  240.     }
  241.     /* Delete the entry itself */
  242.     Tcl_DeleteHashEntry(entry);
  243.   }
  244. }
  245.  
  246. void STk_mark_callbacks(void)
  247. {
  248.   Tcl_HashEntry *entry1, *entry2;
  249.   Tcl_HashSearch search1, search2;
  250.   Tcl_HashTable *secondary;
  251.   char *key;
  252.  
  253.   for (entry1 = Tcl_FirstHashEntry(&Tk_callbacks, &search1);
  254.        entry1;
  255.        entry1 = Tcl_NextHashEntry(&search1)) {
  256.     
  257.     key = Tcl_GetHashKey(&Tk_callbacks, entry1);
  258.     if (*key == 'a' && strncmp(key, "after#", 6) == 0) {
  259.       /* No secondary hash table */
  260.       STk_gc_mark((SCM) Tcl_GetHashValue(entry1));
  261.     }
  262.     else {
  263.       /* We have a secondary hash table. Scan it  */
  264.       secondary = Tcl_GetHashValue(entry1);
  265.       for (entry2 = Tcl_FirstHashEntry(secondary, &search2);
  266.        entry2;
  267.        entry2 = Tcl_NextHashEntry(&search2)) {
  268.     
  269.     STk_gc_mark((SCM) Tcl_GetHashValue(entry2));
  270.       }
  271.     }
  272.   }
  273. }
  274.  
  275. /* 
  276.  * Return the parameters associated to the callback contained (as a string)
  277.  * in the value parameter. If an error occurs, this function returns NULL
  278.  *
  279.  */
  280. char *STk_append_callback_parameters(SCM proc)
  281. {
  282.   SCM param, port;
  283.  
  284.   if (!CLOSUREP(proc)) return NULL;
  285.   param = CLOSURE_PARAMETERS(proc);
  286.  
  287.   if (NULLP(param) || CONSP(param)) {
  288.     port = STk_open_output_string();
  289.     STk_print(Cons(proc, param) , port, TK_MODE); 
  290.     return CHARS(STk_get_output_string(port));
  291.   }
  292.   return NULL;
  293. }
  294.  
  295.  
  296. /******************************************************************************
  297.  *
  298.  * Tcl result manipulation functions
  299.  *
  300.  ******************************************************************************/
  301.  
  302. void STk_sharp_dot_result(Tcl_Interp *interp, char *value)
  303. {
  304.   /* Transform Tcl result in #.result so that it is evaluated when read */
  305.   int len = strlen(value);
  306.   char *s;
  307.  
  308.   s = (char *) STk_must_malloc(len + 3);
  309.   s[0] = '#';
  310.   s[1] = '.';
  311.   strcpy(s+2, value);
  312.   
  313.   Tcl_SetResult(interp, s, TCL_VOLATILE);
  314. }
  315.  
  316. void STk_stringify_result(Tcl_Interp *interp, char *value)
  317. {
  318.   /* Transform Tcl result in "result" with " and \ escaped */
  319.   Tcl_SetResult(interp,  STk_stringify(value, 0), TCL_VOLATILE);
  320. }
  321.  
  322. SCM STk_last_Tk_as_SCM(void)
  323. {
  324.   return STk_last_Tk_result;
  325. }
  326.  
  327. SCM STk_get_NIL_value(void)
  328. {
  329.   return NIL;
  330. }
  331.  
  332.  
  333. /*
  334.  * STk_stringify permits to transform the string "s" in a valid STk string.
  335.  * Original string is deallocated if free_original is 1 
  336.  */
  337.  
  338. char *STk_stringify(char *s, int free_original)
  339. {
  340.   char *res, *d;
  341.   
  342.   if (s == NULL) s = "";
  343.   res = d = must_malloc(2 * strlen(s) + 3); /* worst overestimation */
  344.   
  345.   for ( *d++ = '"'; *s; s++, d++) {
  346.     if (*s == '"' || *s == '\\') *d++ = '\\';
  347.     *d = *s;
  348.   }
  349.   *d++ = '"';
  350.   *d   = '\0';
  351.   
  352.   if (free_original) free(s);
  353.   return res;
  354. }
  355.  
  356.  
  357. /******************************************************************************
  358.  *
  359.  * Motif simulation
  360.  *
  361.  * Tk 4.0 uses a field in the Tk_Window structure to tell the library if it
  362.  * must be conform to Motif look. This field is Tcl_LinkVar'ed.
  363.  *
  364.  ******************************************************************************/
  365.  
  366. static SCM get_Motif(char *s)
  367. {
  368.   TkWindow *p = (TkWindow *) Tk_MainWindow(STk_main_interp);
  369.   return (p->mainPtr->strictMotif) ? Truth: Ntruth;
  370. }
  371.  
  372. static void set_Motif(char *s, SCM value)
  373.   TkWindow *p = (TkWindow *) Tk_MainWindow(STk_main_interp);
  374.   p->mainPtr->strictMotif = !(value == Ntruth);
  375. }
  376.  
  377.  
  378. void STk_init_glue(void)
  379. {
  380.   /* 
  381.    * Take into account the fact that Tk main window  name (i.e. ``.'') 
  382.    * cannot be used in list since it leads to erroneous evaluation 
  383.    * (e.g. [focus .] would produce an error since read will find a malformed
  384.    * pair).
  385.    *
  386.    */
  387.   STk_root_window_name=Intern(ROOT_WINDOW);   STk_gc_protect(&STk_root_window_name);
  388.   STk_root_window     =STk_eval(Sym_dot, NIL);STk_gc_protect(&STk_root_window);
  389.  
  390.   VCELL(STk_root_window_name) = STk_root_window;
  391.  
  392.   /* Init the callback table */
  393.   Tcl_InitHashTable(&Tk_callbacks, TCL_STRING_KEYS);
  394.   
  395.   /* Associate a getter and a setter for the global variable *Tk-strict-Motif*  */
  396.   STk_define_C_variable("*tk-strict-motif*", get_Motif, set_Motif);
  397. }
  398.  
  399. #endif /* USE_TK */
  400.